<template>
  <div class="common-table">
    <div class="table-header" v-if="title || $slots.header || $slots.actions">
      <div class="table-title-area">
        <slot name="header">
          <div class="table-title" v-if="title">{{ title }}</div>
        </slot>
      </div>
      <div class="table-actions" v-if="$slots.actions">
        <slot name="actions"></slot>
      </div>
    </div>
    
    <div class="table-content">
      <el-table
        ref="tableRef"
        v-bind="tableProps"
        v-on="tableEvents"
        :data="data"
        :border="border"
        :stripe="stripe"
        :size="size"
        :fit="fit"
        :show-header="showHeader"
        :highlight-current-row="highlightCurrentRow"
        :row-class-name="rowClassName"
        :row-style="rowStyle"
        :cell-class-name="cellClassName"
        :cell-style="cellStyle"
        :header-row-class-name="headerRowClassName"
        :header-row-style="headerRowStyle"
        :header-cell-class-name="headerCellClassName"
        :header-cell-style="headerCellStyle"
        :lazy="lazy"
        :load="load"
        :tree-props="treeProps"
        :row-key="rowKey"
        :expand-row-keys="expandRowKeys"
        :default-expand-all="defaultExpandAll"
        :show-summary="showSummary"
        :sum-text="sumText"
        :summary-method="summaryMethod"
        :span-method="spanMethod"
        :select-on-indeterminate="selectOnIndeterminate"
        :indent="indent"
        :empty-text="emptyText"
        :default-sort="defaultSort"
        :tooltip-effect="tooltipEffect"
        :show-overflow-tooltip="showOverflowTooltip"
        :align="align"
        :header-align="headerAlign"
        :class-name="className"
        :row-key-name="rowKeyName"
        :show-header-overflow="showHeaderOverflow"
        :show-summary-overflow="showSummaryOverflow"
        :selectable="selectable"
        :reserve-selection="reserveSelection"
        :filter-method="filterMethod"
        :filtered-value="filteredValue"
        :filter-placement="filterPlacement"
        :filter-multiple="filterMultiple"
        :filter-change="filterChange"
        :current-row-key="currentRowKey"
        :row-dblclick="rowDblclick"
        :row-contextmenu="rowContextmenu"
        :row-click="rowClick"
        :row-select="rowSelect"
        :selection-change="selectionChange"
        :select-all="selectAll"
        :cell-mouse-enter="cellMouseEnter"
        :cell-mouse-leave="cellMouseLeave"
        :cell-dblclick="cellDblclick"
        :cell-click="cellClick"
        :header-click="headerClick"
        :header-contextmenu="headerContextmenu"
        @sort-change="handleSortChange"
        @filter-change="handleFilterChange"
        @current-change="handleCurrentChange"
        @header-dragend="handleHeaderDragend"
        @expand-change="handleExpandChange"
      >
        <template v-for="column in columns" :key="column.prop || column.type">
          <el-table-column
            v-bind="column"
            :align="column.align || align"
            :header-align="column.headerAlign || headerAlign"
            :class-name="column.className"
            :label-class-name="column.labelClassName"
            :selectable="column.selectable"
            :reserve-selection="column.reserveSelection"
            :filters="column.filters"
            :filter-method="column.filterMethod"
            :filtered-value="column.filteredValue"
            :filter-placement="column.filterPlacement"
            :filter-multiple="column.filterMultiple"
            :filter-change="column.filterChange"
            :render-header="column.renderHeader"
            :formatter="column.formatter"
            :show-overflow-tooltip="column.showOverflowTooltip !== false"
          >
            <template v-if="column.slot" #[column.slot]="scope">
              <slot :name="column.slot" v-bind="scope"></slot>
            </template>
          </el-table-column>
        </template>
        
        <template #empty>
          <slot name="empty">
            <el-empty :description="emptyText" :image-size="100" />
          </slot>
        </template>
        
        <template #append>
          <slot name="append"></slot>
        </template>
      </el-table>
    </div>
    
    <div class="table-footer" v-if="showPagination || $slots.footer">
      <slot name="footer">
        <div class="table-pagination" v-if="showPagination">
          <el-pagination
            :current-page="currentPage"
            :page-size="pageSize"
            :page-sizes="pageSizes"
            :total="total"
            :layout="paginationLayout"
            :background="paginationBackground"
            :small="paginationSmall"
            :disabled="paginationDisabled"
            @update:page-size="handleSizeChange"
            @update:current-page="handlePageChange"
            @size-change="handleSizeChange"
            @current-change="handlePageChange"
          />
        </div>
      </slot>
    </div>
  </div>
</template>

<script setup>
import { ref, computed, watch } from 'vue'

const props = defineProps({
  // 表格数据
  data: {
    type: Array,
    default: () => []
  },
  // 表格列配置
  columns: {
    type: Array,
    default: () => []
  },
  // 表格标题
  title: {
    type: String,
    default: ''
  },
  // 是否显示边框
  border: {
    type: Boolean,
    default: true
  },
  // 是否显示斑马纹
  stripe: {
    type: Boolean,
    default: true
  },
  // 表格尺寸
  size: {
    type: String,
    default: 'default'
  },
  // 列的宽度是否自撑开
  fit: {
    type: Boolean,
    default: true
  },
  // 是否显示表头
  showHeader: {
    type: Boolean,
    default: true
  },
  // 是否要高亮当前行
  highlightCurrentRow: {
    type: Boolean,
    default: false
  },
  // 行的 className 的回调方法
  rowClassName: {
    type: [String, Function],
    default: ''
  },
  // 行的 style 的回调方法
  rowStyle: {
    type: [Object, Function],
    default: () => ({})
  },
  // 单元格的 className 的回调方法
  cellClassName: {
    type: [String, Function],
    default: ''
  },
  // 单元格的 style 的回调方法
  cellStyle: {
    type: [Object, Function],
    default: () => ({})
  },
  // 表头行的 className 的回调方法
  headerRowClassName: {
    type: [String, Function],
    default: ''
  },
  // 表头行的 style 的回调方法
  headerRowStyle: {
    type: [Object, Function],
    default: () => ({})
  },
  // 表头单元格的 className 的回调方法
  headerCellClassName: {
    type: [String, Function],
    default: ''
  },
  // 表头单元格的 style 的回调方法
  headerCellStyle: {
    type: [Object, Function],
    default: () => ({})
  },
  // 是否懒加载子节点数据
  lazy: {
    type: Boolean,
    default: false
  },
  // 加载子节点数据的函数
  load: {
    type: Function,
    default: () => {}
  },
  // 渲染嵌套数据的配置选项
  treeProps: {
    type: Object,
    default: () => ({
      hasChildren: 'hasChildren',
      children: 'children'
    })
  },
  // 行数据的 Key
  rowKey: {
    type: [String, Function],
    default: ''
  },
  // 展开的行，数组元素为 row-key
  expandRowKeys: {
    type: Array,
    default: () => []
  },
  // 是否默认展开所有行
  defaultExpandAll: {
    type: Boolean,
    default: false
  },
  // 是否在表尾显示合计行
  showSummary: {
    type: Boolean,
    default: false
  },
  // 合计行第一列的文本
  sumText: {
    type: String,
    default: '合计'
  },
  // 自定义的合计计算方法
  summaryMethod: {
    type: Function,
    default: () => {}
  },
  // 合并行或列的计算方法
  spanMethod: {
    type: Function,
    default: () => {}
  },
  // 在多选表格中，当仅有部分行被选中时，点击表头的多选框是否可以选中当前页的所有行
  selectOnIndeterminate: {
    type: Boolean,
    default: true
  },
  // 展示树形数据时，每层缩进的宽度
  indent: {
    type: Number,
    default: 16
  },
  // 空数据时显示的文本内容
  emptyText: {
    type: String,
    default: '暂无数据'
  },
  // 默认的排序列和排序顺序
  defaultSort: {
    type: Object,
    default: () => ({})
  },
  // tooltip effect 属性
  tooltipEffect: {
    type: String,
    default: 'dark'
  },
  // 当内容过长被隐藏时显示 tooltip
  showOverflowTooltip: {
    type: Boolean,
    default: true
  },
  // 对齐方式
  align: {
    type: String,
    default: 'left'
  },
  // 表头对齐方式
  headerAlign: {
    type: String,
    default: 'left'
  },
  // className 的回调方法
  className: {
    type: [String, Function],
    default: ''
  },
  // 行数据的 Key 的名称
  rowKeyName: {
    type: String,
    default: ''
  },
  // 当表头内容过长被隐藏时显示 tooltip
  showHeaderOverflow: {
    type: Boolean,
    default: true
  },
  // 当表尾内容过长被隐藏时显示 tooltip
  showSummaryOverflow: {
    type: Boolean,
    default: true
  },
  // 仅对 type=selection 的列有效，类型为 Function，用于决定某一行是否可以被选中
  selectable: {
    type: Function,
    default: () => true
  },
  // 仅对 type=selection 的列有效，类型为 Boolean，是否在数据更新之后保留之前选中的数据
  reserveSelection: {
    type: Boolean,
    default: false
  },
  // 数据过滤的选项
  filterMethod: {
    type: Function,
    default: () => {}
  },
  // 选中的数据过滤项
  filteredValue: {
    type: Array,
    default: () => []
  },
  // 过滤弹出框的定位方式
  filterPlacement: {
    type: String,
    default: 'bottom-end'
  },
  // 数据过滤的选项是否多选
  filterMultiple: {
    type: Boolean,
    default: true
  },
  // 当表格的筛选条件发生变化的时候会触发该事件
  filterChange: {
    type: Function,
    default: () => {}
  },
  // 当前行的 key
  currentRowKey: {
    type: [String, Number],
    default: ''
  },
  // 当某一行被双击时会触发该事件
  rowDblclick: {
    type: Function,
    default: () => {}
  },
  // 当某一行被鼠标右键点击时会触发该事件
  rowContextmenu: {
    type: Function,
    default: () => {}
  },
  // 当某一行被点击时会触发该事件
  rowClick: {
    type: Function,
    default: () => {}
  },
  // 当某一行被选中时会触发该事件
  rowSelect: {
    type: Function,
    default: () => {}
  },
  // 当选择项发生变化时会触发该事件
  selectionChange: {
    type: Function,
    default: () => {}
  },
  // 当用户手动勾选全选 Checkbox 时触发该事件
  selectAll: {
    type: Function,
    default: () => {}
  },
  // 当单元格 hover 进入时会触发该事件
  cellMouseEnter: {
    type: Function,
    default: () => {}
  },
  // 当单元格 hover 退出时会触发该事件
  cellMouseLeave: {
    type: Function,
    default: () => {}
  },
  // 当某个单元格被双击时会触发该事件
  cellDblclick: {
    type: Function,
    default: () => {}
  },
  // 当某个单元格被点击时会触发该事件
  cellClick: {
    type: Function,
    default: () => {}
  },
  // 当某个表头被点击时会触发该事件
  headerClick: {
    type: Function,
    default: () => {}
  },
  // 当某个表头被鼠标右键点击时触发该事件
  headerContextmenu: {
    type: Function,
    default: () => {}
  },
  // 是否显示分页
  showPagination: {
    type: Boolean,
    default: true
  },
  // 当前页码
  currentPage: {
    type: Number,
    default: 1
  },
  // 每页显示条数
  pageSize: {
    type: Number,
    default: 10
  },
  // 每页显示条数的选择项
  pageSizes: {
    type: Array,
    default: () => [10, 20, 50, 100]
  },
  // 总条数
  total: {
    type: Number,
    default: 0
  },
  // 分页组件布局
  paginationLayout: {
    type: String,
    default: 'total, sizes, prev, pager, next, jumper'
  },
  // 分页按钮背景色
  paginationBackground: {
    type: Boolean,
    default: true
  },
  // 是否使用小型分页
  paginationSmall: {
    type: Boolean,
    default: false
  },
  // 是否禁用分页
  paginationDisabled: {
    type: Boolean,
    default: false
  }
})

const emit = defineEmits([
  'update:currentPage',
  'update:pageSize',
  'sort-change',
  'filter-change',
  'current-change',
  'header-dragend',
  'expand-change',
  'size-change',
  'row-dblclick',
  'row-contextmenu',
  'row-click',
  'row-select',
  'selection-change',
  'select-all',
  'cell-mouse-enter',
  'cell-mouse-leave',
  'cell-dblclick',
  'cell-click',
  'header-click',
  'header-contextmenu'
])

const tableRef = ref(null)

// 表格属性
const tableProps = computed(() => {
  const {
    data,
    border,
    stripe,
    size,
    fit,
    showHeader,
    highlightCurrentRow,
    rowClassName,
    rowStyle,
    cellClassName,
    cellStyle,
    headerRowClassName,
    headerRowStyle,
    headerCellClassName,
    headerCellStyle,
    lazy,
    load,
    treeProps,
    rowKey,
    expandRowKeys,
    defaultExpandAll,
    showSummary,
    sumText,
    summaryMethod,
    spanMethod,
    selectOnIndeterminate,
    indent,
    emptyText,
    defaultSort,
    tooltipEffect,
    showOverflowTooltip,
    align,
    headerAlign,
    className,
    rowKeyName,
    showHeaderOverflow,
    showSummaryOverflow,
    selectable,
    reserveSelection,
    filterMethod,
    filteredValue,
    filterPlacement,
    filterMultiple,
    currentRowKey
  } = props
  
  return {
    data,
    border,
    stripe,
    size,
    fit,
    showHeader,
    highlightCurrentRow,
    rowClassName,
    rowStyle,
    cellClassName,
    cellStyle,
    headerRowClassName,
    headerRowStyle,
    headerCellClassName,
    headerCellStyle,
    lazy,
    load,
    treeProps,
    rowKey,
    expandRowKeys,
    defaultExpandAll,
    showSummary,
    sumText,
    summaryMethod,
    spanMethod,
    selectOnIndeterminate,
    indent,
    emptyText,
    defaultSort,
    tooltipEffect,
    showOverflowTooltip,
    align,
    headerAlign,
    className,
    rowKeyName,
    showHeaderOverflow,
    showSummaryOverflow,
    selectable,
    reserveSelection,
    filterMethod,
    filteredValue,
    filterPlacement,
    filterMultiple,
    currentRowKey
  }
})

// 表格事件
const tableEvents = computed(() => {
  const {
    rowDblclick,
    rowContextmenu,
    rowClick,
    rowSelect,
    selectionChange,
    selectAll,
    cellMouseEnter,
    cellMouseLeave,
    cellDblclick,
    cellClick,
    headerClick,
    headerContextmenu
  } = props
  
  return {
    'row-dblclick': rowDblclick,
    'row-contextmenu': rowContextmenu,
    'row-click': rowClick,
    'row-select': rowSelect,
    'selection-change': selectionChange,
    'select-all': selectAll,
    'cell-mouse-enter': cellMouseEnter,
    'cell-mouse-leave': cellMouseLeave,
    'cell-dblclick': cellDblclick,
    'cell-click': cellClick,
    'header-click': headerClick,
    'header-contextmenu': headerContextmenu
  }
})

// 处理排序变化
const handleSortChange = (sort) => {
  emit('sort-change', sort)
}

// 处理筛选变化
const handleFilterChange = (filters) => {
  emit('filter-change', filters)
}

// 处理当前行变化
const handleCurrentChange = (currentRow, oldCurrentRow) => {
  emit('current-change', currentRow, oldCurrentRow)
}

// 处理表头拖动结束
const handleHeaderDragend = (newWidth, oldWidth, column, event) => {
  emit('header-dragend', newWidth, oldWidth, column, event)
}

// 处理展开行变化
const handleExpandChange = (row, expanded) => {
  emit('expand-change', row, expanded)
}

// 处理每页显示条数变化
const handleSizeChange = (size) => {
  emit('update:pageSize', size)
  emit('size-change', size)
}

// 处理页码变化
const handlePageChange = (page) => {
  emit('update:currentPage', page)
  emit('current-change', page)
}

// 暴露方法给父组件
defineExpose({
  getTableRef: () => tableRef.value,
  clearSelection: () => tableRef.value?.clearSelection(),
  toggleRowSelection: (row, selected) => tableRef.value?.toggleRowSelection(row, selected),
  toggleAllSelection: () => tableRef.value?.toggleAllSelection(),
  toggleRowExpansion: (row, expanded) => tableRef.value?.toggleRowExpansion(row, expanded),
  setCurrentRow: (row) => tableRef.value?.setCurrentRow(row),
  clearSort: () => tableRef.value?.clearSort(),
  clearFilter: (columnKeys) => tableRef.value?.clearFilter(columnKeys),
  doLayout: () => tableRef.value?.doLayout(),
  sort: (prop, order) => tableRef.value?.sort(prop, order)
})
</script>

<style lang="scss" scoped>
.common-table {
  background: var(--el-bg-color-overlay);
  border-radius: var(--el-border-radius-base);
  box-shadow: var(--el-box-shadow-lighter);
  overflow: hidden;
  
  .table-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 12px 20px;
    border-bottom: 1px solid var(--el-border-color-lighter);
    
    .table-title-area {
      .table-title {
        font-size: 16px;
        font-weight: 500;
        color: var(--el-text-color-primary);
      }
    }
    
    .table-actions {
      display: flex;
      gap: 8px;
    }
  }
  
  .table-content {
    :deep(.el-table) {
      --el-table-border-color: var(--el-border-color-lighter);
      --el-table-header-bg-color: var(--el-fill-color-light);
      --el-table-row-hover-bg-color: var(--el-fill-color-lighter);
      --el-table-current-row-bg-color: var(--el-color-primary-light-9);
      --el-table-header-text-color: var(--el-text-color-primary);
      --el-table-text-color: var(--el-text-color-regular);
      
      &::before {
        height: 0;
      }
      
      th.el-table__cell {
        background-color: var(--el-table-header-bg-color);
        color: var(--el-table-header-text-color);
        font-weight: 500;
      }
      
      td.el-table__cell {
        color: var(--el-table-text-color);
      }
      
      .el-table__row {
        &:hover > td.el-table__cell {
          background-color: var(--el-table-row-hover-bg-color);
        }
        
        &.current-row > td.el-table__cell {
          background-color: var(--el-table-current-row-bg-color);
        }
      }
    }
  }
  
  .table-footer {
    padding: 12px 20px;
    border-top: 1px solid var(--el-border-color-lighter);
    
    .table-pagination {
      display: flex;
      justify-content: flex-end;
    }
  }
}
</style>